package TP5;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * Clase que fue pensada para administrar la simulación.
 */
public class Simulador {

    private final double tiempoSimulacion;
    private double tiempoEntreLlegadasClientesLimiteInferior;
    private double tiempoEntreLlegadasClientesLimiteSuperior;
    private double tiempoParaDespacharClienteLimiteInferior;
    private double tiempoParaDespacharClienteLimiteSuperior;
    private double tiempoEntreLlegadasRepositorLimiteInferior;
    private double tiempoEntreLlegadasRepositorLimiteSuperior;
    private double tiempoMinimoReposicion;
    private double tiempoReposicionPorLata;
    private double tiempoMinimoAdicionalCambio;
    private double tiempoPorLataRetirada;
    private VectorEstado actual;

    /**
     * Recibe sólo el tiempo de simulación, y configura el resto de los
     * parámetros de tiempo tal y como dice el enunciado dado.
     *
     * @param tiempoSimulacion tiempo total de simulación
     */
    public Simulador(double tiempoSimulacion) {
        this.tiempoSimulacion = tiempoSimulacion;
        tiempoEntreLlegadasClientesLimiteInferior = 0.5;
        tiempoEntreLlegadasClientesLimiteSuperior = 3.5;
        tiempoEntreLlegadasRepositorLimiteInferior = 660;
        tiempoEntreLlegadasRepositorLimiteSuperior = 780;
        tiempoParaDespacharClienteLimiteInferior = 2.5;
        tiempoParaDespacharClienteLimiteSuperior = 3.5;
        tiempoMinimoReposicion = 10.0;
        tiempoReposicionPorLata = 1 / 6;
        tiempoMinimoAdicionalCambio = 2.0;
        tiempoPorLataRetirada = 1 / 6;

        Expendedor expendedor = new Expendedor(40, 20, 20, 80);

        actual = new VectorEstado(expendedor);
    }

    /**
     * Recibe el tiempo de simulación y el resto de los parámetros configurables
     * de tiempo.
     *
     * @param tiempoSimulacion tiempo total de simulación, en minutos.
     * @param tiempoEntreLlegadasClientesLimiteInferior el mínimo del intervalo
     * de tiempos de llegada de los clientes al expendedor, en minutos.
     * @param tiempoEntreLlegadasClientesLimiteSuperior el máximo del intervalo
     * de tiempos de llegada de los clientes al expendedor, en minutos.
     * @param tiempoParaDespacharClienteLimiteInferior el mínimo del intervalo
     * de tiempos que tarda el expendedor en despachar a los clientes, una vez
     * que empiezan a ser atendidos, en minutos.
     * @param tiempoParaDespacharClienteLimiteSuperior el máximo del intervalo
     * de tiempos que tarda el expendedor en despachar a los clientes, una vez
     * que empiezan a ser atendidos, en minutos.
     * @param tiempoEntreLlegadasRepositorLimiteInferior el mínimo tiempo entre
     * llegadas del repositor, en minutos.
     * @param tiempoEntreLlegadasRepositorLimiteSuperior el máximo tiempo entre
     * llegadas del repositor, en minutos.
     * @param tiempoMinimoReposicion tiempo mínimo de reposición, en minutos.
     * @param tiempoReposicionPorLata tiempo adicional que tarda el repositor,
     * por lata, en minutos.
     * @param tiempoMinimoAdicionalCambio tiempo mínimo que tarda el repositor
     * en caso de tener que cambiar los stocks iniciales de las gaseosas, en
     * minutos.
     * @param tiempoPorLataRetirada tiempo adicional que tarda el repositor, por
     * lata, en minutos.
     */
    public Simulador(double tiempoSimulacion, double tiempoEntreLlegadasClientesLimiteInferior, double tiempoEntreLlegadasClientesLimiteSuperior, double tiempoParaDespacharClienteLimiteInferior, double tiempoParaDespacharClienteLimiteSuperior, double tiempoEntreLlegadasRepositorLimiteInferior, double tiempoEntreLlegadasRepositorLimiteSuperior, double tiempoMinimoReposicion, double tiempoReposicionPorLata, double tiempoMinimoAdicionalCambio, double tiempoPorLataRetirada) {
        this.tiempoSimulacion = tiempoSimulacion;
        this.tiempoEntreLlegadasClientesLimiteInferior = tiempoEntreLlegadasClientesLimiteInferior;
        this.tiempoEntreLlegadasClientesLimiteSuperior = tiempoEntreLlegadasClientesLimiteSuperior;
        this.tiempoParaDespacharClienteLimiteInferior = tiempoParaDespacharClienteLimiteInferior;
        this.tiempoParaDespacharClienteLimiteSuperior = tiempoParaDespacharClienteLimiteSuperior;
        this.tiempoEntreLlegadasRepositorLimiteInferior = tiempoEntreLlegadasRepositorLimiteInferior;
        this.tiempoEntreLlegadasRepositorLimiteSuperior = tiempoEntreLlegadasRepositorLimiteSuperior;
        this.tiempoMinimoReposicion = tiempoMinimoReposicion;
        this.tiempoReposicionPorLata = tiempoReposicionPorLata;
        this.tiempoMinimoAdicionalCambio = tiempoMinimoAdicionalCambio;
        this.tiempoPorLataRetirada = tiempoPorLataRetirada;
    }

    public VectorEstado obtenerVector() {
        double tiempoEntreLlegadasCliente = actual.getRndLlegadaCliente() * (tiempoEntreLlegadasClientesLimiteSuperior - tiempoEntreLlegadasClientesLimiteInferior) + tiempoEntreLlegadasClientesLimiteInferior;
        actual.setTiempoEntreLlegadasCliente(tiempoEntreLlegadasCliente);
        actual.setProximaLlegadaCliente(actual.getReloj() + tiempoEntreLlegadasCliente);



        return null;
    }

    /**
     * realiza la simulacion y guarda en un ArrayList los vectorEstado 
     * que tiene que imprimir
     *
     * @return Lista de vectorEstado que se imprimen
     * @param minutosDesde tiempo de simulacion que se empieza a imprimir el vector
     * @param minutosHasta tiempo de simulacion hasta donde se imprime el vector
     */
    public ArrayList<VectorEstado> obtenerSimulacion(double minutosDesde, double minutosHasta) {
        ArrayList<VectorEstado> datos = new ArrayList<VectorEstado>();
         actual.setEvento(Evento.INICIAL);
        while (tiempoSimulacion > actual.getReloj()) {
            calcularProximoVector();
            if (actual.getReloj() > minutosDesde && actual.getReloj() < minutosHasta) {
                datos.add(actual);
            }
            datos.add(actual);
        }
        return datos;
    }

    private Evento siguienteEvento() {
        return Evento.INICIAL;
    }

    public void calcularProximoVector() {
        VectorEstado nuevo = new VectorEstado(actual);
        nuevo.setReloj(actual.getRelojEventoProximo());
        nuevo.setEvento(actual.getSiguienteEvento());
        nuevo.getEvento().calcularProximaLlegada(nuevo);
          actual=nuevo;


    }
}
